#if !defined(EA_8534EBEC_C351_40a1_A543_91A07B941E3E__INCLUDED_)
#define EA_8534EBEC_C351_40a1_A543_91A07B941E3E__INCLUDED_

#include "Item.h"
#include "Client.h"
#include "Exceptions.h"
#include "AuxFunctions.h"
#include "SeeMenus.h"
#include <vector>
#include <stdlib.h>
#include <fstream>
#include <queue>

struct compareItems {
	bool operator()(const Item* it1, const Item* it2) {

		int it1_quant = it1->getQuantity();
		int it2_quant = it2->getQuantity();
		bool res = false;
		//it1 age = 1/12/1800 && it2 age = 1/12/1900 -> 1800 < 1900 -> true
		if ((it1->getAge() > it2->getAge())
		    || (it1->getAge() == it2->getAge() && it1_quant < it2_quant))
			res = true;

		return res;
	}
};

class Inventory {
public:
	Inventory() {}
	virtual ~Inventory() {}

	/** @return the inventory size */
	int getInventorySize() const {
		return items.size();
	}

	/** @return the vector items */
	vector<Item> getItems() const {
		return items;
	}
	/** @return the vector types */
	vector<Type> getTypes() const {
		return types;
	}
	/** Sets item equal to _item */
	void setItem(Item _item);

	/** Sets items equal to _items */
	void setItems(vector<Item> _items) { items = _items; }

	/** Sets types equal to _types */
	void setTypes(vector<Type> _types) { types = _types; }

	/** as long as it doesn't exist already in the inventory it can be added */
	void addItem(Item item);
	/** removes from the inventory the item in the memory address given */
	void removeItem(Item* _item);

	/** Adds a new Type to the inventory */
	void addType(Type type);

	/** @return a vector with all the maintypes in the inventory */
	vector<string> uniqueMaintypes();

	/** @return a vector with all the subtypes in the inventory */
	vector<string> uniqueSubtypes();

	/** shows all the items in the inventory */
	void showInventory();
	
	/** shows all the items of the given client */
	void showInventory(Client* _client);
	
	/** shows all the items of the given vector<Item*> */
	void showItems(vector<Item*> _items);
	
	/** shows all the item types that exist */
	void showTypes();
	
	/** chose an item type and edit its information */
	void editItemType();
	
	/** chose an item type and delete it */
	void deleteItemType();
	
	/** @return the index in the vector types of the type chosen */
	int chosenType();

	/** @return the quantity of x items with same name and Type
	 *  @param name name of item
	 *  @param type type of item*/
	int quantity(string name, Type type);

	/** updates the price of the item given
	 * @param item the item that will have its price updated*/
	void updateItemPrice(Item item);

	/** Creates item for owner _owner */
	void createItem(string _owner);

	/** returns true if the Type given already exists in the vector<Types> types */
	bool typeExists(Type _type);

	/** @return a vector of pointers to the objects in the vector items*/
	vector<Item*> itemsP();

	/** @return the Item with the ID given
	 *  @param itemID ID of item*/
	Item searchItemByID(unsigned int itemID);

	/** items search by name
	 * @return the items found in the search */
	vector<Item*> itemsSearch();
	
	/** items search by maintype
	 * @return the items found in the search */
	vector<Item*> itemsSearchByMaintype();
	
	/** items search by subtype
	 * @return the items found in the search */
	vector<Item*> itemsSearchBySubtype();
	
	/** items search by ID
	 * @return the items found in the search */
	vector<Item*> itemsSearchByID();
	
	/** items search by Age
	 * @return the items found in the search */
	vector<Item*> itemsSearchByAge();
	
	/** items search by Price
	 * @return the items found in the search */
	vector<Item*> itemsSearchByPrice();

	/** @return the items of client _client
	 *  @param _client Chosen Client*/
	vector<Item*> getClientItems(Client* _client);

	/** Initializes the quantity of items in every item */
	void initializeItemsQuantity();
	
	/** Updates the quantity of the item with name and type given */
	void updateQuantity(string name, Type type, int quantity);

	/* ======================================================
	 Priority_queue
	 ======================================================== */

	/** initializes priority_queue rareItems, called in load function */
	void initializeRareItems();
	
	/** @return priority_queue rareItems */
	priority_queue<Item*, vector<Item*>, compareItems> getRareItems() { return rareItems; }
	
	/** adds the last item created to rareItems */
	void updateRareItems();
	
	/** removes _item from rareItems */
	void removeFromRareItems(Item* _item);
private:
	vector<Item> items;
	vector<Type> types;

	priority_queue<Item*, vector<Item*>, compareItems> rareItems;
};

#endif // !defined(EA_8534EBEC_C351_40a1_A543_91A07B941E3E__INCLUDED_)
